package com.example.liujinliang.servicebestpractice.util;

import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;

import com.example.liujinliang.servicebestpractice.callback.DownloadListener;
import com.example.liujinliang.servicebestpractice.common.ConstStatus;
import com.example.liujinliang.servicebestpractice.common.DownloadTaskStat;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 实现下载功能，继承 AsyncTask
 * 注意观察泛型对应着三个函数的参数
 * 分别表示传到后台的参数类型
 * 表示进度条进度的参数类型
 * 表示任务处理结果的参数类型
 */
public class DownloadTask extends AsyncTask<String, Integer, Integer> {

    /**
     * 下载、监听回调状态接口
     */
    private DownloadListener downloadListener;

    /**
     * 下载取消状态，默认没有取消
     */
    private boolean isCandeled = false;

    /**
     * 下载暂停状态，默认没有暂停
     */
    private boolean isPaused = false;

    private int lastProgress;

    public DownloadTask(DownloadListener listener) {
        downloadListener = listener;
    }

    /**
     * 处理耗时工作：下载任务
     *
     * @param params
     * @return
     */
    @Override
    protected Integer doInBackground(String... params) {
        File file = null;
        InputStream inputStream = null;
        RandomAccessFile savedFile = null;

        if (params.length == 0 || params == null) {
            return DownloadTaskStat.TYPE_SUCCESS.getCode();
        }

        try {

            // 初始化 downloadedLength
            long downloadedLength = 0;

            // 初始化 downloadUrl
            String downloadUrl = params[0];

            // 初始化 fileName
            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));

            // 初始化 directory
            String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();

            // 根据 Url 生成文件
            file = new File(directory + fileName);

            if (file.exists()) {
                downloadedLength = file.length();
            }

            // 获取待下载资源的大小
            long contentLength = getContentLength(downloadUrl);

            if (contentLength == 0) {
                return DownloadTaskStat.TYPE_FAILED.getCode();
            } else if (contentLength == downloadedLength) {
                return DownloadTaskStat.TYPE_SUCCESS.getCode();
            }

            // 初始化 OKHttpClient
            OkHttpClient okHttpClient = new OkHttpClient();

            // 初始化 Request
            Request request = new Request.Builder()
                    // 断点下载，指定从哪个字节开始下载
                    .addHeader("RANGE", "bytes=" + downloadedLength + "-")
                    .url(downloadUrl)
                    .build();

            // 初始化 Response
            Response response = okHttpClient.newCall(request).execute();

            if (response != null) {
                inputStream = response.body().byteStream();
                savedFile = new RandomAccessFile(file, "rw");
                savedFile.seek(downloadedLength);

                byte[] b = new byte[1024];
                int total = 0;
                int len = 0;

                while ((len = inputStream.read(b)) != -1) {
                    if (isCandeled) {
                        return DownloadTaskStat.TYPE_FAILED.getCode();
                    }
                    if (isPaused) {
                        return DownloadTaskStat.TYPE_FAILED.getCode();
                    } else {
                        total += len;
                        savedFile.write(b, 0, len);

                        // 记录已下载的百分比
                        int progress = (int) ((total + downloadedLength) * 100 / contentLength);

                        // 更新进度
                        publishProgress(progress);
                    }
                }
                response.body().close();
                return DownloadTaskStat.TYPE_SUCCESS.getCode();
            }

        } catch (IOException e) {
            Log.i("【关闭IO流异常】:", e.getMessage());
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (savedFile != null) {
                    savedFile.close();
                }
                if (isCandeled && file != null) {
                    file.delete();
                }
            } catch (IOException e) {
                Log.i("【关闭IO流异常】:", e.getMessage());
            }
        }

        return DownloadTaskStat.TYPE_SUCCESS.getCode();
    }

    /**
     * 获取待下载资源大小
     *
     * @param downloadUrl
     * @return
     * @throws IOException
     */
    private long getContentLength(String downloadUrl) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();

        Request request = new Request.Builder()
                .url(downloadUrl)
                .build();

        Response response = okHttpClient.newCall(request).execute();

        if (response != null) {
            long contentLength = response.body().contentLength();
            response.body().close();
            return contentLength;
        }

        return 0;
    }

    /**
     * 处理UI更新
     *
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        int progress = values[0];
        if (progress > lastProgress) {
            downloadListener.onProgress(progress);
            lastProgress = progress;
        }
    }

    /**
     * 将结果返回
     *
     * @param status
     */
    @Override
    protected void onPostExecute(Integer status) {

        switch (status) {
            case ConstStatus.TYPE_SUCCESS:
                downloadListener.onSuccess();
                break;
            case ConstStatus.TYPE_FAILED:
                downloadListener.onFailed();
                break;
            case ConstStatus.TYPE_PAUSED:
                downloadListener.onPaused();
                break;
            case ConstStatus.TYPE_CANCELED:
                downloadListener.onCanceled();
                break;
            default:
                break;
        }
    }

    public void pauseDownload() {
        isPaused = true;
    }

    public void cancelDownload() {
        isCandeled = true;
    }
}
